﻿using System.Text.RegularExpressions;
using System.Windows.Media;
using DimensionsHelper.Client.Helpers;
using DimensionsHelper.Common.Contracts;
using DimensionsHelper.Common.Contracts.TableFormatter.Options;
using DimensionsHelper.Common.Utils;

namespace DimensionsHelper.Client.ViewModels.CsvFormatter;

public partial class SigComparisonMapViewModel(IServiceProvider serviceProvider)
    : ObservableCollection<SigComparisonViewModel>, IProjectOption<SigComparisonMap>
{
    private readonly Dictionary<string, SigComparisonViewModel> _compMap = [];
    private readonly CsvFormatterViewModel _project = serviceProvider.GetRequiredService<CsvFormatterViewModel>();


    public bool TryWriteOption(SigComparisonMap target)
    {
        foreach (SigComparisonViewModel comparison in this)
        {
            WriteSigComparison(target, comparison);
        }

        return true;
    }


    public void LoadOption(SigComparisonMap source)
    {
        Clear();
        _compMap.Clear();

        foreach (SigComparison comparison in source.Comparisons)
        {
            string key = GetComparisonMapKey(comparison);
            string simpleKey = GetSimpleKey(comparison);

            // 首先检查simpleKey
            // 1. 如果simpleKey存在，key不存在，将ColumnA和ColumnB调换顺序，加入表达式。
            // 2. 如果simpleKey和key都存在，将原始表达式加入到已有表达式中。
            // 3. 如果simpleKey不存在，使用已有SigComparision对象添加新的ViewModel配置对象。

            if (_compMap.TryGetValue(simpleKey, out SigComparisonViewModel? viewModel))
            {
                viewModel.JoinExpression(_compMap.TryGetValue(key, out _)
                    ? comparison.ExpressionA
                    : comparison.ExpressionB);
            }
            else
            {
                viewModel = new SigComparisonViewModel();
                Add(viewModel);

                viewModel.JoinExpression(comparison.ExpressionA);
                viewModel.MarkType = comparison.MarkType;
                viewModel.ConflictOperations.FromEnumValue(comparison.BorderMarkConflictFlags,
                    EnumStringCache.GetEnumDescriptionMap<SigComparisonBorderMarkConflictFlags>(),
                    EnumStringCache.GetIncompatibleDescription(typeof(SigComparisonBorderMarkConflictFlags)));
                viewModel.CharAtMarkColumnColor = comparison.CharAtMarkColumnColor.ToColor();
                viewModel.CharAtAnotherColumnColor = comparison.CharAtAnotherColumnColor.ToColor();
                viewModel.StartStringToSkip = comparison.StartCharactersToSkip;

                _compMap.Add(key, viewModel);
                _compMap.Add(simpleKey, viewModel);
            }
        }
    }


    [GeneratedRegex(@"[\s\/\\]*")]
    private static partial Regex SpaceOrSeparatorRegex();


    private void WriteSigComparison(SigComparisonMap map, SigComparisonViewModel sigComparison)
    {
        if (sigComparison.Expression.Length < 2 || (sigComparison.CharAtMarkColumnColor == Colors.Transparent &&
                                                    sigComparison.CharAtAnotherColumnColor == Colors.Transparent))
        {
            _project.ReportService?.Warn(ProjectErrorMessages.SigTestExpressionIsInvalid, sigComparison.Expression);
            return;
        }

        string[] expressions = SpaceOrSeparatorRegex().Replace(sigComparison.Expression,
            match => string.IsNullOrWhiteSpace(match.Value) ? "" : ",").Split(',');

        foreach (string expr in expressions)
        {
            if (expr.Length < 2)
            {
                _project?.ReportService?.Warn(ProjectErrorMessages.SigTestExpressionIsTooShort, expr);
                continue;
            }

            char a = expr[0];
            char b = expr[1];

            if (!char.IsLetter(a) || !char.IsLetter(b) || a == b)
            {
                _project?.ReportService?.Warn(ProjectErrorMessages.SigTestExpressionIsInvalid, expr);
                continue;
            }

            if (!map.TryAdd(a, b, out SigComparison? comp))
            {
                _project?.ReportService?.Warn(ProjectErrorMessages.SigTestExpressionIsExist, expr);
                continue;
            }

            comp.MarkType = sigComparison.MarkType;
            comp.BorderMarkConflictFlags = sigComparison.ConflictOperations.ToEnumFlags(
                EnumStringCache.GetEnumDescriptionMap<SigComparisonBorderMarkConflictFlags>(),
                EnumStringCache.GetIncompatibleDescription(typeof(SigComparisonBorderMarkConflictFlags)));
            comp.CharAtMarkColumnColor = sigComparison.CharAtMarkColumnColor.ToExcelStyleColor();
            comp.CharAtAnotherColumnColor = sigComparison.CharAtAnotherColumnColor.ToExcelStyleColor();
            comp.StartCharactersToSkip = sigComparison.StartStringToSkip;
        }
    }


    private static string GetComparisonMapKey(SigComparison comp)
    {
        return
            $"{EnumStringCache.SigComparisonMarkTypeNames[(int)comp.MarkType]}|{comp.MarkColumn}|{comp.AnotherColumn}|{comp.CharAtMarkColumnColor}|{comp.CharAtAnotherColumnColor}";
    }


    private static string GetSimpleKey(SigComparison comp)
    {
        return
            $"{EnumStringCache.SigComparisonMarkTypeNames[(int)comp.MarkType]}|{comp.CharAtMarkColumnColor}|{comp.CharAtAnotherColumnColor}";
    }
}